import random
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

'''
梯度上升法 缺点在于每次更新系数，都需要遍历整个数据集，样本数、特征值太多，复杂度太高
转为用随机梯度上升法
'''

def load_data_set():
    data_list = []
    label_list = []
    fr = open('test_set.txt', 'r', encoding='utf-8')
    for line in fr.readlines():
        line_arr = line.strip().split()
        data_list.append([1.0, float(line_arr[0]), float(line_arr[1])])
        label_list.append(int(line_arr[2]))
    return data_list, label_list

def sigmoid(x_in):
    return 1.0 / (1 + np.exp(-x_in))

def stoc_grad_ascent0(data_list, label_list):
    data_arr = np.array(data_list)
    m, n = np.shape(data_arr)
    alpha = 0.01
    weights = np.ones((n, 1))
    for i in range(m):
        tmp = np.dot(data_arr[i], weights)
        h = sigmoid(tmp)
        error = label_list[i] - h
        weights = weights + alpha * error * data_arr[i].reshape(3,1)
    return weights


def stoc_grad_ascent1(data_list, label_list, num_iter=100):
    data_arr = np.array(data_list)
    m, n = np.shape(data_arr)
    weights = np.ones((n, 1))
    for j in range(num_iter):
        for i in range(m):
            alpha = 4 / (1.0 + i + j) + 0.01
            rand_index = int(random.uniform(0, m))
            tmp = np.dot(data_arr[rand_index], weights)
            h = sigmoid(tmp)
            error = label_list[rand_index] - h
            weights = weights + alpha * error * data_arr[rand_index].reshape(n,1)
            np.delete(data_arr, rand_index, axis=0)
    return weights

def grad_ascent(data_list, label_list):
    data_mat = np.mat(data_list)
    label_mat = np.mat(label_list).transpose()
    m, n = np.shape(data_mat)
    alpha = 0.001
    max_cycles = 500
    weights = np.ones((n, 1))
    for k in range(max_cycles):
        h = sigmoid(data_mat * weights)
        error = (label_mat - h)
        weights = weights + alpha * data_mat.transpose() * error
    return weights

def plot_best_fit(weights, data_list, label_list):
    data_arr = np.array(data_list)
    m, n = np.shape(data_arr)
    x_cord1 = []
    y_cord1 = []
    x_cord2 = []
    y_cord2 = []
    for i in range(m):
        if int(label_list[i]) == 1:
            x_cord1.append(data_arr[i, 1])
            y_cord1.append(data_arr[i, 2])
        else:
            x_cord2.append(data_arr[i, 1])
            y_cord2.append(data_arr[i, 2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(x_cord1, y_cord1, s=30, c='red', marker='s')
    ax.scatter(x_cord2, y_cord2, s=30, c='green', )
    x = np.arange(-3.0, 3.0, 0.1).reshape([1, 60])
    y = (-weights[0] - weights[1] * x) / weights[2]
    
    x = x.tolist()[0]
    y = y.tolist()[0]
    ax.plot(x, y)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()
    plt.close()


'''
从疝气病预测病马死亡率-------------------------------------------------------
'''
def classify_vector(x_in, weights):
    tmp = np.dot(x_in, weights)
    prob = sigmoid(tmp)
    if prob > 0.5:
        return 1.0
    else:
        return 0.0

def colic_test():
    fr_train = open('horse_colic_training.txt', 'r')
    fr_test = open('horse_colic_test.txt', 'r')
    train_set = []
    train_labels = []
    for line in fr_train.readlines():
        curr_line = line.strip().split('\t')
        line_arr = []
        for i in range(21):
            line_arr .append(float(curr_line[i]))
        train_set.append(line_arr)
        train_labels.append(float(curr_line[21]))
    train_weights = stoc_grad_ascent1(train_set, train_labels, 500)
    error_count = 0
    num_test_vec = 0.0
    for line in fr_test.readlines():
        num_test_vec += 1.0
        curr_line = line.strip().split('\t')
        line_arr = []
        for i in range(21):
            line_arr .append(float(curr_line[i]))
        if int(classify_vector(line_arr, train_weights)) != int(curr_line[21]):
            error_count += 1

    error_rate = float(error_count) / num_test_vec
    print('the error rate of the test is {}'.format(error_rate))
    return error_rate


def multitest():
    num_tests = 10
    error_sum = 0.0
    for k in range(num_tests):
        error_sum +=colic_test()
    print('after {} iterrations the averge error rate is :{} '.format(num_tests, error_sum/float(num_tests)))












if __name__ == '__main__':
    data_list, label_list = load_data_set()
    # weights = grad_ascent(data_list, label_list)
    weights0 = stoc_grad_ascent0(data_list, label_list)
    weights1 = stoc_grad_ascent1(data_list, label_list, 200)
    plot_best_fit(weights1, data_list, label_list)

    multitest()

#    sss = np.dot(data_list, qqq)
#    www = sigmoid(sss)
    



